package com.derbysoft.dswitch.adapter.ihg.dswitch2.service.handler;

import com.derbysoft.dswitch.adapter.ihg.common.domain.Direction;
import com.derbysoft.dswitch.adapter.ihg.common.domain.OperationType;
import com.derbysoft.dswitch.adapter.ihg.common.domain.ReservationLog;
import com.derbysoft.dswitch.adapter.ihg.common.log.LogBody;
import com.derbysoft.dswitch.adapter.ihg.common.log.LogDetailPair;
import com.derbysoft.dswitch.adapter.ihg.common.log.PerformanceLogger;
import com.derbysoft.dswitch.adapter.ihg.common.log.TransactionLogger;
import com.derbysoft.dswitch.adapter.ihg.common.utils.EnvironmentUtils;
import com.derbysoft.dswitch.adapter.ihg.dswitch2.HotelProviderService;
import com.derbysoft.dswitch.adapter.ihg.dswitch2.service.handler.RemoteServiceHandler;
import com.derbysoft.dswitch.adapter.ihg.dswitch2.service.impl.ReservationIDUtils;
import com.derbysoft.remote.dswitch.core.GenericRQ;
import com.derbysoft.remote.dswitch.core.GenericRS;
import com.derbysoft.remote.dswitch.hotel.dto.HotelReservationRQ;
import com.derbysoft.remote.dswitch.hotel.dto.HotelReservationRS;
import org.springframework.util.StopWatch;

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

/**
 * Created by: jason
 * Date: 2012-06-01
 */
public class HotelPreviewHandler
        implements RemoteServiceHandler<GenericRQ<HotelReservationRQ>, GenericRS<HotelReservationRS>> {

    private HotelProviderService<GenericRQ<HotelReservationRQ>, GenericRS<HotelReservationRS>> hotelProviderService;

    @Override
    public GenericRS<HotelReservationRS> invoke(GenericRQ<HotelReservationRQ> request) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        TransactionLogger.getReservationLogger().set(createReservationLog(request));

        GenericRS<HotelReservationRS> response = hotelProviderService.invoke(request);

        stopWatch.stop();

        long elapsedTime = stopWatch.getTotalTimeMillis();
        TransactionLogger.getReservationLogger().get().setTimeSpan(elapsedTime);

        if (EnvironmentUtils.appendDerbyLog()) {
            appendLogDetail(request, response, elapsedTime);
        }

        if (response.getErrors() != null) {
            TransactionLogger.getReservationLogger().get().setError(true);
            TransactionLogger.getReservationLogger().get().setException(response.getErrors().getErrorList().get(0).getMessage());
            PerformanceLogger.append(LogBody.PROCESSED_RESULT, LogBody.ProcessResult.Fail.name());
        } else {
            PerformanceLogger.append(LogBody.PROCESSED_RESULT, LogBody.ProcessResult.Success.name());
        }
        return response;
    }

    private void appendLogDetail(GenericRQ<HotelReservationRQ> request, GenericRS<HotelReservationRS> response, long elapsedTime) {
        Set<LogDetailPair> logDetails = TransactionLogger.getLogDetails().get();
        if (logDetails == null) {
            logDetails = new HashSet<LogDetailPair>();
        }
        logDetails.add(LogDetailPair.build(request, Direction.FROM_CHANNEL));
        logDetails.add(LogDetailPair.build(response, Direction.TO_CHANNEL));
        TransactionLogger.getLogDetails().set(logDetails);
        TransactionLogger.getReservationLogger().get().setTimeSpan(elapsedTime);
    }

    protected ReservationLog createReservationLog(GenericRQ<HotelReservationRQ> request) {
        ReservationLog reservationLog = new ReservationLog();
        reservationLog.setId(UUID.randomUUID().toString());
        reservationLog.setTaskId(request.getHeader().getTaskId());
        reservationLog.setChannel(request.getHeader().getSource().getUniqueID().getId());
        reservationLog.setErsp(ReservationIDUtils.getErspNo(request.getPayload().getHotelReservationIDs()).getResIDValue());
        reservationLog.setHotels(request.getPayload().getHotelReservation().getHotelRef().getCode());
        reservationLog.setOperationType(OperationType.HOTEL_PREVIEW);
        return reservationLog;
    }

    public void setHotelProviderService(HotelProviderService<GenericRQ<HotelReservationRQ>, GenericRS<HotelReservationRS>> hotelProviderService) {
        this.hotelProviderService = hotelProviderService;
    }
}
